package com.ruoyi.point.controller;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.pojo.WebSocketPushInfo;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.websocket.WebSocketUsers;
import com.ruoyi.framework.pojo.VirInfo;
import com.ruoyi.framework.point.PointTable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.access.prepost.PreAuthorize;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

@RestController
@Slf4j
public class DosingController extends BaseController {

    @Autowired
    private PointTable pointTable;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private TokenService tokenService;

    @PreAuthorize("@ss.hasRole('admin')")
    @PostMapping("/read/current")
    public TableDataInfo getCurrent(@RequestBody Object device) {
        startPage();
        JSONObject jsonObject = new JSONObject(device);
        Object deviceName = jsonObject.get("deviceName");
        Object parameters = jsonObject.get("parameters");
        if (parameters.toString().contains("$")) {
            Object value = jsonObject.get("value");
            List<? extends VirInfo> read = pointTable.read(deviceName.toString(), parameters.toString(), value);
            return getDataTable(read);
        } else {
            TableDataInfo dataInfo = new TableDataInfo();
            dataInfo.setCode(500);
            dataInfo.setMsg("parametersError");
            return dataInfo;
        }

    }

    @PreAuthorize("@ss.hasRole('admin,user')")
    @PostMapping("/write")
    public AjaxResult getWrite(@RequestBody JsonNode objects, HttpServletRequest request) {
        if (objects.isObject()) {
            String deviceName = objects.get("deviceName").asText();
            String parameters = objects.get("parameters").asText();
            if (deviceName.equals("Picker")){
                parameters = parameters + '.' + tokenService.getLoginUser(request).getUserId();
            }
            Object value = objects.get("value");
            return AjaxResult.msg(pointTable.write(deviceName,parameters, value));
        } else if (objects.isArray()) {
           List<Boolean> writeResult = new ArrayList<>();
            for (JsonNode o : objects) {
                ObjectNode objectNode = (ObjectNode) o;
                String parameters = objectNode.get("parameters").asText();
                String deviceName = objectNode.get("deviceName").asText();
                Object value = objectNode.get("value");
                writeResult.add(pointTable.write(deviceName,parameters, value));
            }
            boolean result = writeResult.stream().allMatch(Boolean::booleanValue);
            return AjaxResult.msg(result);
        }
        return null;
    }


    @GetMapping("/getToken")
    public AjaxResult getToken() {
        return AjaxResult.success(getTokenId());
    }

    @PreAuthorize("@ss.hasRole('admin')")
    @PostMapping("/subscriptionData")
    public TableDataInfo subscriptionData(@RequestBody Object device) {
        startPage();
        JSONObject jsonObject = new JSONObject(device);
        Object deviceName = jsonObject.get("deviceName");
        Object parameters = jsonObject.get("parameters");
        if (parameters.toString().contains("$")) {
            Object value = jsonObject.get("value");
            String deviceNameStr = deviceName.toString();
            String parametersStr = parameters.toString();
            String valueStr = null;
            if (null != value){
                valueStr = value.toString();
            }
            WebSocketUsers.addSubscriptions(getTokenId(), deviceNameStr,parametersStr,valueStr);
            return getDataTable(pointTable.read(deviceNameStr, parameters.toString(), value));
        } else {
            TableDataInfo dataInfo = new TableDataInfo();
            dataInfo.setCode(500);
            dataInfo.setMsg("parametersError");
            return dataInfo;
        }

    }

    @PreAuthorize("@ss.hasRole('admin')")
    @PostMapping("/subscriptionData/remove")
    public TableDataInfo subscriptionDataRemove(@RequestBody Object device) {
        startPage();
        JSONObject jsonObject = new JSONObject(device);
        Object deviceName = jsonObject.get("deviceName");
        Object parameters = jsonObject.get("parameters");
        if (parameters.toString().contains("$")) {
            Object value = jsonObject.get("value");
            String deviceNameStr = deviceName.toString();
            String parametersStr = parameters.toString();
            String valueStr = null;
            if (null != value){
                valueStr = value.toString();
            }
            WebSocketUsers.removeSubscriptions(getTokenId(), deviceNameStr,parametersStr,valueStr);
            return getDataTable(pointTable.read(deviceName.toString(), parameters.toString(), value));
        } else {
            TableDataInfo dataInfo = new TableDataInfo();
            dataInfo.setCode(500);
            dataInfo.setMsg("parametersError");
            return dataInfo;
        }

    }

    private static void updateExistingData(ArrayNode conditionData, ArrayNode existingData) {
        for (JsonNode conditionItem : conditionData) {
            Iterator<String> conditionFieldNames = conditionItem.fieldNames();
            while (conditionFieldNames.hasNext()) {
                String conditionFieldName = conditionFieldNames.next();
                String conditionFieldValue = conditionItem.get(conditionFieldName).asText();
                Iterator<JsonNode> existingIterator = existingData.elements();
                while (existingIterator.hasNext()) {
                    JsonNode existingItem = existingIterator.next();
                    String existingFieldValue = existingItem.get(conditionFieldName).asText();
                    if (conditionFieldValue.equals(existingFieldValue)) {
                        // 更新现有数据对象的值
                        copyFields(conditionItem, existingItem);
                        break; // 找到匹配项后跳出循环
                    }
                }
            }
        }
    }



    @PostMapping("/push/test")
    public void subscriptionDataRemove(@RequestBody String infos) {
        WebSocketUsers.sendMessageToUserByText(getTokenId(),null,infos);
    }



    private static void copyFields(JsonNode source, JsonNode target) {
        Iterator<String> fieldNames = source.fieldNames();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            JsonNode fieldValue = source.get(fieldName);
            if (!target.has(fieldName)) {
                ((ObjectNode) target).put(fieldName, fieldValue);
            } else {
                ((ObjectNode) target).replace(fieldName, fieldValue);
            }
        }
    }



    String getTokenId() {
        Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            if (user.getUser().getUserName().equals(SecurityUtils.getUsername())) {
                return user.getToken();
            }
        }
        return null;
    }
}
